//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"
#include "type_traits.h"
#include "allocator.h"
#include "algobase.h"
#include "memory.h"
#include "forward.h"

FC_NAMESPACE_BEGIN


template <class T, class Allocator>
class vector_base
{
public:
	typedef vector_base<T, Allocator>			this_type;
	typedef Allocator							allocator_type;

	vector_base()
		: m_begin(0), m_end(0), m_capacity(0), m_allocator()
		{
		}

	explicit vector_base( const allocator_type& alloc )
		: m_begin(0), m_end(0), m_capacity(0), m_allocator(alloc)
		{
		}

	vector_base( const this_type& x )
		: m_begin(0), m_end(0), m_capacity(0), m_allocator()
		{
		}

	~vector_base()
		{
			fc::destroy_range(m_begin, m_end);
			deallocate();
		}

	allocator_type& get_allocator() { return m_allocator; }
	const allocator_type& get_allocator() const { return m_allocator; }
	void set_allocator( const allocator_type& alloc ) { m_allocator = alloc; }

	// this operation is O(1) only if allocators are comparable
	void swap( this_type& x )
	{
		if( m_allocator == x.m_allocator )
		{
			fc::swap( m_begin, x.m_begin );
			fc::swap( m_end, x.m_end );
			fc::swap( m_capacity, x.m_capacity );
		}
		else
		{
			this_type temp(*this);
			*this = x;
			x = temp;
		}
	}

protected:
	T* allocate( size_t n )
	{
		return (T*)(n ? m_allocator.allocate( n * sizeof(T) ) : 0);
	}

	void deallocate()
	{
		if( m_begin )
			m_allocator.deallocate( (void*)m_begin, size_t(m_end - m_begin) * sizeof(T) );
	}

	template <class ForwardIterator>
	T* allocate_copy( size_t newCapacity, ForwardIterator first, ForwardIterator last )
	{
		T* p = allocate(newCapacity);
		fc::uninitialized_copy( first, last, p );
		return p;
	}

	T* allocate_fill( size_t newCapacity, const T& value )
	{
		T* p = allocate(newCapacity);
		fc::uninitialized_fill_n( p, newCapacity, value );
		return p;
	}

	T* m_begin;
	T* m_end;
	T* m_capacity;
	allocator_type m_allocator;
};



FC_NAMESPACE_END

